package top.cardone.data.service;

import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DataAccessException;
import org.springframework.transaction.annotation.Transactional;
import top.cardone.core.util.action.Action1;

import java.util.List;
import java.util.Map;

/**
 * 创建、查询、修改、删除 service
 *
 * @author yao hai tao
 */
public interface CrudService extends java.io.Serializable {
    /**
     * 删除
     *
     * @param delete
     * @return 影响行数
     */
    int delete(Object delete);

    @CacheEvict(allEntries = true)
    default int deleteCache(Object delete) {
        return this.delete(delete);
    }

    int deleteByFuncId(String funcId, Object delete);

    @CacheEvict(allEntries = true)
    default int deleteByFuncIdCache(String funcId, Object delete) {
        return this.deleteByFuncId(funcId, delete);
    }

    /**
     * 删除
     *
     * @return 影响行数
     */
    int deleteAll();

    @CacheEvict(allEntries = true)
    default int deleteAllCache() {
        return this.deleteAll();
    }

    /**
     * 删除
     *
     * @param ids 等于那些属性
     * @return 影响行数
     */
    int deleteByIds(Object ids);

    @CacheEvict(allEntries = true)
    default int deleteByIdsCache(Object ids) {
        return this.deleteByIds(ids);
    }

    /**
     * 删除
     *
     * @param deleteList
     * @return 影响行数
     */
    @Transactional
    int[] deleteList(List<Object> deleteList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] deleteListCache(List<Object> deleteList) {
        return this.deleteList(deleteList);
    }

    @Transactional
    int[] deleteListByFuncId(String funcId, List<Object> deleteList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] deleteListByFuncIdCache(String funcId, List<Object> deleteList) {
        return this.deleteListByFuncId(funcId, deleteList);
    }

    /**
     * 查询
     *
     * @param findList 等于那些属性
     * @return 对象集合
     */
    List<Map<String, Object>> findList(Object findList);

    @Cacheable
    default List<Map<String, Object>> findListCache(Object findList) {
        return this.findList(findList);
    }

    List<Map<String, Object>> findListByFuncId(String funcId, Object findList);

    @Cacheable
    default List<Map<String, Object>> findListByFuncIdCache(String funcId, Object findList) {
        return this.findListByFuncId(funcId, findList);
    }

    /**
     * 查询
     *
     * @param findOne 等于那些属性
     * @return 返回对象
     */
    Map<String, Object> findOne(Object findOne);

    @Cacheable
    default Map<String, Object> findOneCache(Object findOne) {
        return this.findOne(findOne);
    }

    Map<String, Object> findOneByFuncId(String funcId, Object findOne);

    @Cacheable
    default Map<String, Object> findOneByFuncIdCache(String funcId, Object findOne) {
        return this.findOneByFuncId(funcId, findOne);
    }

    /**
     * 插入
     *
     * @param insert 对象
     * @return 影响行数
     */
    int insert(Object insert);

    @CacheEvict(allEntries = true)
    default int insertCache(Object insert) {
        return this.insert(insert);
    }

    int insertByFuncId(String funcId, Object insert);

    @CacheEvict(allEntries = true)
    default int insertByFuncIdCache(String funcId, Object insert) {
        return this.insertByFuncId(funcId, insert);
    }

    /**
     * 插入
     *
     * @param insert 对象
     * @return 影响行数
     */
    int insertByNotExists(Object insert);

    @CacheEvict(allEntries = true)
    default int insertByNotExistsCache(Object insert) {
        return this.insertByNotExists(insert);
    }

    /**
     * 插入
     *
     * @param insertList 对象
     * @return 影响行数
     */
    @Transactional
    int[] insertList(List<Object> insertList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] insertListCache(List<Object> insertList) {
        return this.insertList(insertList);
    }

    @Transactional
    int[] insertListByFuncId(String funcId, List<Object> insertList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] insertListByFuncIdCache(String funcId, List<Object> insertList) {
        return this.insertListByFuncId(funcId, insertList);
    }

    /**
     * 插入
     *
     * @param insertList 对象
     * @return 影响行数
     */
    @Transactional
    int[] insertListByNotExists(List<Object> insertList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] insertListByNotExistsCache(List<Object> insertList) {
        return this.insertListByNotExists(insertList);
    }

    /**
     * 查询
     *
     * @param readList
     * @return 返回数据
     */
    List<Object> readList(Object readList);

    @Cacheable
    default List<Object> readListCache(Object readList) {
        return this.readList(readList);
    }

    List<Object> readListByFuncId(String funcId, Object readList);

    @Cacheable
    default List<Object> readListByFuncIdCache(String funcId, Object readList) {
        return this.readListByFuncId(funcId, readList);
    }

    /**
     * 查询
     *
     * @param readOne
     * @return 返回数据
     */
    Object readOne(Object readOne);

    @Cacheable
    default Object readOneCache(Object readOne) {
        return this.readOne(readOne);
    }

    Object readOneByFuncId(String funcId, Object readOne);

    @Cacheable
    default Object readOneByFuncIdCache(String funcId, Object readOne) {
        return this.readOneByFuncId(funcId, readOne);
    }

    /**
     * 保存
     *
     * @param save 保存对象
     * @return 插入后数据库值
     */
    @Transactional
    int save(Object save);

    @CacheEvict(allEntries = true)
    @Transactional
    default int saveCache(Object save) {
        return this.save(save);
    }

    @Transactional
    int saveByFuncId(String funcId, Object save);

    @CacheEvict(allEntries = true)
    @Transactional
    default int saveByFuncIdCache(String funcId, Object save) {
        return this.saveByFuncId(funcId, save);
    }

    /**
     * 更新
     *
     * @param update 对象
     * @return 影响行数
     */
    int update(Object update);

    @CacheEvict(allEntries = true)
    default int updateCache(Object update) {
        return this.update(update);
    }

    int updateByFuncId(String funcId, Object update);

    @CacheEvict(allEntries = true)
    default int updateByFuncIdCache(String funcId, Object update) {
        return this.updateByFuncId(funcId, update);
    }

    /**
     * 更新
     *
     * @param updateList 对象
     * @return 影响行数
     */
    @Transactional
    int[] updateList(List<Object> updateList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] updateListCache(List<Object> updateList) {
        return this.updateList(updateList);
    }

    @Transactional
    int[] updateListByFuncId(String funcId, List<Object> updateList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] updateListByFuncIdCache(String funcId, List<Object> updateList) {
        return this.updateListByFuncId(funcId, updateList);
    }

    /**
     * 保存
     *
     * @param saveList 对象
     * @return 影响行数
     */
    @Transactional
    int[] saveList(List<Object> saveList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] saveListCache(List<Object> saveList) {
        return this.saveList(saveList);
    }

    @Transactional
    int[] saveListByFuncId(String funcId, List<Object> saveList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] saveListByFuncIdCache(String funcId, List<Object> saveList) {
        return this.saveListByFuncId(funcId, saveList);
    }

    /**
     * 关键字查询
     *
     * @param findList 关键字查询条件
     * @return 关键字查询数据
     */
    List<Map<String, Object>> findListByKeyword(Map<String, Object> findList);

    @Cacheable
    default List<Map<String, Object>> findListByKeywordCache(Map<String, Object> findList) {
        return this.findListByKeyword(findList);
    }

    /**
     * 用于判断缓存是否被 @CacheEvict(allEntries = true) 刷新
     * 应用场景：定义了布隆过滤器，载入了所有用户编号用于防缓存击穿，可以有办法进行判断用户数据有变更
     *
     * @return
     */
    @Cacheable
    default Long currentTimeMillisCache() {
        return System.currentTimeMillis();
    }

    /**
     * 执行sql
     *
     * @param sql
     */
    void execute(String sql);

    /**
     * 执行sql
     *
     * @param sql
     */
    @Transactional
    int[] batchUpdate(String... sql);

    /**
     * 插入
     *
     * @param insert 对象
     * @return 影响行数
     */
    int insertOnConflict(Object insert);

    @CacheEvict(allEntries = true)
    default int insertOnConflictCache(Object insert) {
        return this.insertOnConflict(insert);
    }

    /**
     * 插入
     *
     * @param insertList 对象
     * @return 影响行数
     */
    @Transactional
    int[] insertListOnConflict(List<Object> insertList);

    @CacheEvict(allEntries = true)
    @Transactional
    default int[] insertListOnConflictCache(List<Object> saveList) {
        return this.insertListOnConflict(saveList);
    }

    /**
     * 保存
     *
     * @param save 对象
     * @return 影响行数
     */
    @Transactional
    int saveOnConflict(Object save);

    /**
     * 保存
     *
     * @param save 对象
     * @return 影响行数
     */
    @Transactional
    @CacheEvict(allEntries = true)
    default int saveOnConflictCache(Object save) {
        return this.saveOnConflict(save);
    }

    /**
     * 保存
     *
     * @param saveList 对象
     * @return 影响行数
     */
    @Transactional
    int[] saveListOnConflict(List<Object> saveList);

    @Transactional
    @CacheEvict(allEntries = true)
    default int[] saveListOnConflictCache(List<Object> saveList) {
        return this.saveListOnConflict(saveList);
    }


    @Transactional
    @CacheEvict(allEntries = true)
    default Map<String, Object> executeCache(Map<String, Object> execute) {
        return this.execute(execute);
    }

    @Transactional
    default Map<String, Object> execute(Map<String, Object> execute) {
        Map<String, Object> output = Maps.newHashMap();

        for (Map.Entry<String, Object> executeEntry : execute.entrySet()) {
            if (StringUtils.endsWith(executeEntry.getKey(), "insert")) {
                output.put(executeEntry.getKey(), this.insert(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "saveList")) {
                output.put(executeEntry.getKey(), this.saveList((List<Object>) executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "save")) {
                output.put(executeEntry.getKey(), this.save(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "insertByNotExists")) {
                output.put(executeEntry.getKey(), this.insertByNotExists(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "insertOnConflict")) {
                output.put(executeEntry.getKey(), this.insertOnConflict(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "insertList")) {
                output.put(executeEntry.getKey(), this.insertList((List<Object>) executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "insertListByNotExists")) {
                output.put(executeEntry.getKey(), this.insertListByNotExists((List<Object>) executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "insertListOnConflict")) {
                output.put(executeEntry.getKey(), this.insertListOnConflict((List<Object>) executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "update")) {
                output.put(executeEntry.getKey(), this.update(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "updateList")) {
                output.put(executeEntry.getKey(), this.updateList((List<Object>) executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "readOne")) {
                output.put(executeEntry.getKey(), this.readOne(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "readList")) {
                output.put(executeEntry.getKey(), this.readList(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "findOne")) {
                output.put(executeEntry.getKey(), this.findOne(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "findList")) {
                output.put(executeEntry.getKey(), this.findList(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "delete")) {
                output.put(executeEntry.getKey(), this.delete(executeEntry.getValue()));
            } else if (StringUtils.endsWith(executeEntry.getKey(), "deleteList")) {
                output.put(executeEntry.getKey(), this.deleteList((List<Object>) executeEntry.getValue()));
            }
        }

        return output;
    }

    @CacheEvict(allEntries = true)
    default int executeQueryByFuncIdCache(String funcId, Object param) {
        return this.executeQueryByFuncId(funcId, param);
    }

    int executeQueryByFuncId(String funcId, Object param);

    @CacheEvict(allEntries = true)
    default int deleteBySqlFileNameCache(String sqlFileName, Object delete) {
        return this.deleteBySqlFileName(sqlFileName, delete);
    }

    int deleteBySqlFileName(String sqlFileName, Object delete);

    @Cacheable
    default List<Map<String, Object>> findListBySqlFileNameCache(String sqlFileName, Object findList) {
        return this.findListBySqlFileName(sqlFileName, findList);
    }

    List<Map<String, Object>> findListBySqlFileName(String sqlFileName, Object findList);

    @Cacheable
    default Map<String, Object> findOneBySqlFileNameCache(String sqlFileName, Object findOne) {
        return this.findOneBySqlFileName(sqlFileName, findOne);
    }

    Map<String, Object> findOneBySqlFileName(String sqlFileName, Object findOne);

    @Transactional
    @CacheEvict(allEntries = true)
    default int executeQueryBySqlFileNameCache(String sqlFileName, Object param, Action1<Map<String, Object>> action) throws DataAccessException {
        return this.executeQueryBySqlFileName(sqlFileName, param, action);
    }

    @Transactional
    int executeQueryBySqlFileName(String sqlFileName, Object param, Action1<Map<String, Object>> action) throws DataAccessException;

    @Transactional
    @CacheEvict(allEntries = true)
    default <T> int executeQueryBySqlFileNameCache(String sqlFileName, Object param, Class<T> elementType, Action1<T> action) throws DataAccessException {
        return this.executeQueryBySqlFileName(sqlFileName, param, elementType, action);
    }

    @Transactional
    <T> int executeQueryBySqlFileName(String sqlFileName, Object param, Class<T> elementType, Action1<T> action) throws DataAccessException;

    @Cacheable
    default List<Object> readListBySqlFileNameCache(String sqlFileName, Object readList) {
        return this.readListBySqlFileName(sqlFileName, readList);
    }

    List<Object> readListBySqlFileName(String sqlFileName, Object readList);

    @Cacheable
    default Object readOneBySqlFileNameCache(String sqlFileName, Object readOne) {
        return this.readOneBySqlFileName(sqlFileName, readOne);
    }

    Object readOneBySqlFileName(String sqlFileName, Object readOne);

    @Transactional
    @CacheEvict(allEntries = true)
    default int saveBySqlFileNameCache(String updateSqlFileName, String insertSqlFileName, Object save) {
        return this.saveBySqlFileName(updateSqlFileName, insertSqlFileName, save);
    }

    @Transactional
    int saveBySqlFileName(String updateSqlFileName, String insertSqlFileName, Object save);

    @Transactional
    @CacheEvict(allEntries = true)
    default int updateBySqlFileNameCache(String sqlFileName, Object update) {
        return this.updateBySqlFileName(sqlFileName, update);
    }

    @Transactional
    int updateBySqlFileName(String sqlFileName, Object update);

    @Transactional
    @CacheEvict(allEntries = true)
    default int[] updateListBySqlFileNameCache(String sqlFileName, List<Map<String, Object>> updateList) {
        return this.updateListBySqlFileName(sqlFileName, updateList);
    }

    @Transactional
    int[] updateListBySqlFileName(String sqlFileName, List<Map<String, Object>> updateList);
}
